using System;
using System.Collections;
using System.Collections.Generic;
using System.Text;
using NUnit.Framework;
using Stratman.Utilities.NetFlix;

namespace Stratman.Utilities.NetFlix.UnitTests
{
    /// <summary>
    /// Contains a series of unit tests for the NetFlixSession class.
    /// </summary>
    [TestFixture]
    public class NetFlixSessionTests
    {
        /// <summary>
        /// Session object that we will use for the duration of the test run.
        /// </summary>
        protected NetFlixSession session = null;
        /// <summary>
        /// Registration email that will be used when logging the user in.
        /// </summary>
        protected const string loginEmail = "[Add your NetFlix email address here]";
        /// <summary>
        /// Password that will be used when logging the user in.
        /// </summary>
        protected const string loginPassword = "[Add your NetFlix password here]";

        /// <summary>
        /// Setup logic for this test fixture that will establish the session that will be used
        /// for the duration of the run.
        /// </summary>
        [TestFixtureSetUp]
        public void SetUp()
        {
            LogIn();
        }

        /// <summary>
        /// Tries to log the user in to NetFlix.
        /// </summary>
        [Test]
        public void SuccessfulLogin()
        {
            LogIn();
        }

        /// <summary>
        /// A negative test that will try to log the user in using a bogus set of credentials.
        /// </summary>
        [Test]
        public void FailedLogin()
        {
            try
            {
                NetFlixSession session = new NetFlixSession("thereisnowaythisexists@email.com", "somebadpassword");
            }

            catch (LoginFailedException exception)
            {
                string warningTrap = exception.Message;
                return;
            }

            Assert.IsTrue(false, "The login attempt succeeded when it should have failed.");
        }

        /// <summary>
        /// Retrieves the movie details for The Big Lebowski.
        /// </summary>
        [Test]
        public void MovieDetailsTheBigLebowski()
        {
            Movie movie = session.GetMovie(1181532);

            Assert.AreEqual(1998, movie.Details.Year, "The movie's release year should be 1998.");
            Assert.AreEqual("Comedy", movie.Details.Genre, "The movie's genre should be Comedy.");
            Assert.AreEqual("R", movie.Details.MpaaRating, "The movie's MPAA rating should be R.");
            Assert.AreEqual(1181532, movie.ID, "The movie's ID should be 1181532.");
            Assert.AreEqual("The Big Lebowski", movie.Title, "The movie's title should be The Big Lebowski.");
        }

        /// <summary>
        /// Retrieves the contents of the user's queue.
        /// </summary>
        [Test]
        public void Queue()
        {
            Dictionary<long, Movie> queueMovies = session.GetQueue();
            Assert.Greater(queueMovies.Count, 0, "There should be movies in the queue.");
        }

        /// <summary>
        /// Retrieves the list of movies that the user currently has at home.
        /// </summary>
        [Test]
        public void MoviesAtHome()
        {
            Dictionary<long, Movie> homeMovies = session.GetMoviesAtHome();
            Assert.Greater(homeMovies.Count, 0, "There should be movies at home.");
        }

        /// <summary>
        /// Retrieves the list of recommendations that NetFlix has made for the current user.
        /// </summary>
        [Test]
        public void Recommendations()
        {
            Dictionary<long, Movie> recommendedMovies = session.GetRecommendations();
            Assert.Greater(recommendedMovies.Count, 0, "There should be available recommendations.");
        }

        /// <summary>
        /// Retrieves the list of movies that have recently been shipped to the user.
        /// </summary>
        [Test]
        public void RecentlyShipped()
        {
            Dictionary<long, Movie> shippedMovies = session.GetRecentlyShippedMovies();
            Assert.Greater(shippedMovies.Count, 0, "There should be recently shipped movies.");
        }

        /// <summary>
        /// Retrieves the list of movies that the user has recently returned to NetFlix.
        /// </summary>
        [Test]
        public void RecentlyReceived()
        {
            Dictionary<long, Movie> receivedMovies = session.GetRecentlyReceivedMovies();
            Assert.Greater(receivedMovies.Count, 0, "There should be recently received movies.");
        }

        /// <summary>
        /// Retrieves the list of new releases.
        /// </summary>
        [Test]
        public void NewReleases()
        {
            Dictionary<long, Movie> newReleases = session.GetNewReleases();
            Assert.Greater(newReleases.Count, 0, "There should be new releases.");
        }

        /// <summary>
        /// Retrieves the list of the top 100 most-rented movies.
        /// </summary>
        [Test]
        public void Top100()
        {
            Dictionary<long, Movie> top100 = session.GetTop100();
            Assert.AreEqual(top100.Count, 100, "There should be 100 movies in the top 100.");
        }

        /// <summary>
        /// Searches the movie database for those matching "the office".
        /// </summary>
        [Test]
        public void SearchTheOffice()
        {
            Dictionary<long, Movie> results = session.FindMovies("the office");
            Assert.Greater(results.Count, 50, "Search term \"the office\" should return more than 50 results.");
        }

        /// <summary>
        /// Searches the Watch Now database for those matching "the office".
        /// </summary>
        [Test]
        public void SearchWatchableTheOffice()
        {
            Dictionary<long, Movie> results = session.FindWatchableMovies("the office");
            Assert.Greater(results.Count, 0, "Search term \"the office\" should return watchable movies.");
        }

        /// <summary>
        /// A negative test that searches the movie database with a bogus search term.
        /// </summary>
        [Test]
        public void SearchNoResults()
        {
            Dictionary<long, Movie> results = session.FindMovies("sladfjlsdjfaldf");
            Assert.AreEqual(results.Count, 0, "Search term \"sladfjlsdjfaldf\" should return no results.");
        }

        /// <summary>
        /// A negative test that searches the Watch Now database with a bogus search term.
        /// </summary>
        [Test]
        public void SearchWatchableNoResults()
        {
            Dictionary<long, Movie> results = session.FindWatchableMovies("sladfjlsdjfaldf");
            Assert.AreEqual(results.Count, 0, "Search term \"sladfjlsdjfaldf\" should return no watchable movies.");
        }

        /// <summary>
        /// Retrieves the list of genres on NetFlix's site.
        /// </summary>
        [Test]
        public void GetGenres()
        {
            List<Genre> results = session.GetGenres();
            Assert.Greater(results.Count, 50, "There should be more than 50 genres.");
        }

        /// <summary>
        /// Performs a series of operations on the user's queue using The Big Lebowski:  first it
        /// is added to the queue, then moved to the top of the queue, and finally it is removed.
        /// </summary>
        [Test]
        public void AddBigLebowskiToQueue()
        {
            session.AddToQueue(1181532);
            Dictionary<long, Movie> queue = session.GetQueue();

            if (!queue.ContainsKey(1181532))
                Assert.IsTrue(false, "The Big Lebowski should be in the queue.");

            session.ReorderQueue(1181532, 1);
            queue = session.GetQueue();

            IEnumerator keys = queue.Keys.GetEnumerator();
            keys.MoveNext();

            Assert.AreEqual((long)keys.Current, 1181532, "The Big Lebowski should be at the front of the queue.");

            session.DeleteFromQueue(1181532);
            queue = session.GetQueue();

            Assert.IsFalse(queue.ContainsKey(1181532), "The Big Lebowski should no longer be in the queue.");
        }

        /*[Test]
        public void BrowseAction()
        {
            bool nextPageExists = false;
            Dictionary<long, Movie> movies = session.BrowseGenre(new Genre(296, "Action & Adventure"), 1, ref nextPageExists);

            Assert.GreaterOrEqual(movies.Count, 10, "There should be at least 10 movies on the Action & Adventure first page.");
            Assert.IsTrue(nextPageExists, "There should be multiple pages in the Action & Adventure genre.");
        }

        [Test]
        public void BrowseActionSecondPage()
        {
            bool nextPageExists = false;
            Dictionary<long, Movie> movies = session.BrowseGenre(new Genre(296, "Action & Adventure"), 4, ref nextPageExists);

            Assert.GreaterOrEqual(movies.Count, 20, "There should be at least 20 movies on the Action & Adventure second page.");
            Assert.IsTrue(nextPageExists, "There should be a third page in the Action & Adventure genre.");
        }*/

        /// <summary>
        /// Tear down logic for this test fixture that logs out the current session, if necessary.
        /// </summary>
        [TestFixtureTearDown]
        public void TearDown()
        {
            if (session != null)
                session.Dispose();
        }

        /// <summary>
        /// Creates a session object with the hardcoded credentials.
        /// </summary>
        protected void LogIn()
        {
            session = new NetFlixSession(loginEmail, loginPassword);
        }
    }
}
